package com.apes.scm.voucher.service.builder;

import com.apes.framework.api.SpringManager;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.InventoryConsign;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.service.InventoryConsignService;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.account.method.Batch;
import com.apes.scm.account.method.BatchMethod;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.model.DeptEnum;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherService;
import com.apes.scm.voucher.service.VoucherType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 功能：销售订单凭证构造器
 *
 * @author xul
 * @create 2018-10-18 9:26
 */
@Component
public class SaleOrderVoucherBuilder extends AbstractVoucherBuilder {

    @Autowired
    private InventoryConsignService inventoryConsignService;

    @Autowired
    private InventoryService inventoryService;

    public SaleOrderVoucherBuilder() {
        this.voucherType = VoucherType.CUSTOMER_SALE;
        this.BusinessTypes = new String[]{BusinessType.SALE_ORDER};
    }

    /**
     * 功能：创建凭证
     *
     * @param voucher
     */
    @Override
    public Voucher create(Voucher voucher) {
        voucher.setReturned(false);

        if (!("Customer".equals(voucher.getPartner().getRole().getId()))) {
            throw new RuntimeException("销售凭证请指定客户角色的合作伙伴[" + voucher.getPartner().getId() + "]!");
        }

        /**保存凭证**/
        voucher = save(voucher);

        /**跨公司/公司间交易**/
        crossCompanyTransaction(voucher);

        /**成本核算/价值评估**/
        costing(voucher);

        /**增加客户寄售库存**/
        customerConsign(voucher);

        /**账单：用于跨公司内部交易记帐**/
        if (voucher.isInvoiced() && voucher.getInventoryMode().equals(InventoryMode.IM_OWN)) {
            invoiced(voucher);
        }

        return voucher;
    }

    /**
     * 增加客户寄售库存
     */
    private void customerConsign(Voucher voucher) {
        if (!voucher.getInventoryMode().equals(InventoryMode.IM_CONSIGN)) return;
        HashSet<InventoryConsign> inventoryConsigns = new HashSet<>();
        for (VoucherItem voucherItem : voucher.getVoucherItems()) {
            if (voucherItem.getInventoryBatch() != null) {
                InventoryConsign inventoryConsign = createInventoryConsign(voucher, voucherItem, voucherItem.getInventoryBatch(), voucherItem.computeBaseQty());
                inventoryConsigns.add(inventoryConsign);
            } else {
                Dept dept = voucher.getDept();
                if (dept == null) {
                    throw new RuntimeException("业务凭证销售部门为空！");
                }
                if (!(dept.existDeptType(DeptEnum.RETAIL) || dept.existDeptType(DeptEnum.SALE))) {
                    throw new RuntimeException("业务凭证部门为非销售部门！");
                }
                if (!dept.existDeptType(DeptEnum.PURCHASE)) {
                    throw new RuntimeException("业务凭证部门为非采购部门！");
                }

                new BatchMethod<Batch>() {
                    @Override
                    public Iterable wrap() {
                        List<InventoryBatch> inventories = inventoryService.findInventoryBatchForSaleOrder(voucher.getCompany(), dept, voucherItem.getProduct());
                        return inventoryService.wrapBatch(inventories, voucherItem.baseUom(), inventory -> inventory.getBalanceQty() - inventory.getFrostQty());
                    }

                    @Override
                    public void succeed(Batch batch, double increment) {
                        InventoryBatch inventoryBatch = (InventoryBatch) batch.getEntity();
                        inventoryService.changeFrostQty(inventoryBatch, voucherItem.baseUom(),
                                increment, inventoryBatch.getCompany(),
                                voucher.getInnerBusinessType(), voucher.getInnerBusinessKey(),
                                String.valueOf(voucherItem.getId()), "客户寄售冻结批次");
                        InventoryConsign inventoryConsign = createInventoryConsign(voucher, voucherItem, inventoryBatch, increment);
                        inventoryConsigns.add(inventoryConsign);
                    }

                    @Override
                    public void error(double surplus) {
                        throw new RuntimeException("商品：["+voucherItem.getProduct().getId()+"]" + voucherItem.getProduct().getName() + " 价值库存数量少 " + surplus + voucherItem.baseUom().getName() + "！");
                    }
                }.execute(voucherItem.computeBaseQty());
            }
        }
        inventoryConsignService.consign(inventoryConsigns);
    }

    private InventoryConsign createInventoryConsign(Voucher voucher, VoucherItem voucherItem, InventoryBatch inventoryBatch, double consignQty) {
        InventoryConsign inventoryConsign = new InventoryConsign();
        inventoryConsign.setBatchNumber(voucherItem.getId());
        inventoryConsign.setCompany(voucher.getCompany());
        inventoryConsign.setDept(voucher.getDept());
        inventoryConsign.setCustomer(voucher.getPartner());
        inventoryConsign.setProduct(voucherItem.getProduct());
        inventoryConsign.setUom(voucherItem.baseUom());
        inventoryConsign.setTax(voucherItem.getTax());
        inventoryConsign.setPriceUnit(voucherItem.computeBasePrice());
        inventoryConsign.setConsignQty(consignQty);
        inventoryConsign.changeBalanceQty(consignQty);
        /**如果指定了批次，则库存已冻结**/
        inventoryConsign.setInventoryBatch(inventoryBatch);
        return inventoryConsign;
    }

    /**
     * 功能：凭证冲销
     *
     * @param voucher 原销售凭证
     * @return 零售退货凭证
     */
    @Override
    public Voucher writeOff(Voucher voucher) {
        return createRetailReturnVoucher(voucher);
    }

    /**
     * 客户销售凭证退回
     *
     * @param voucher
     * @return
     */
    private Voucher createRetailReturnVoucher(Voucher voucher) {
        Voucher retailReturnVoucher = new Voucher();
        retailReturnVoucher.setBusinessType(BusinessType.SALE_RETURN);
        String[] fields = {"company", "partner", "contract", "dept", "clerk", "inventoryMode", "accountingMethod", "originBusinessType", "origin"};
        ReflectUtil.copy(voucher, retailReturnVoucher, fields);
        retailReturnVoucher.setSourceBusinessType(voucher.getInnerBusinessType());
        retailReturnVoucher.setSource(voucher.getId());
        retailReturnVoucher.setReturned(true);
        retailReturnVoucher.setCustomerExpand(voucher.getCustomerExpand());

        retailReturnVoucher.setVoucherItems(voucher.getVoucherItems().stream().map(
                vItem -> {
                    VoucherItem voucherItem = new VoucherItem();
                    voucherItem.setProduct(vItem.getProduct());
                    voucherItem.setTax(vItem.getTax());
                    voucherItem.setOwner(vItem.obtainOwner());
                    voucherItem.setUom(vItem.getUom());
                    voucherItem.setProductQty(-1 * Math.abs(vItem.getProductQty()));
                    voucherItem.setPriceUnit(vItem.getPriceUnit());
                    voucherItem.setOriginItemId(vItem.getOriginItemId());
                    voucherItem.setSourceItemId(vItem.getSourceItemId());

                    voucherItem.setVoucherItem(vItem);
                    voucherItem.setVoucher(retailReturnVoucher);

                    return voucherItem;
                }).collect(Collectors.toSet())
        );
        return SpringManager.getBean(VoucherService.class).save(retailReturnVoucher);
    }


}
